#include "fila.hh"

// adiciona um novo documento na árvore, seguindo os conceitos de fila (FIFO) e heap: ou seja, põe os elementos por ordem de prioridade
void Fila::adicionarDocumento(Documento* novo){
  heap.push_back(novo); // adiciona o novo documento na árvore
  int indice = heap.size() - 1; // ID do índice: recebe o tamanho da árvore menos um
  while (indice != 0){ // enquanto o índice for maior que 0
    int pai = (indice - 1) / 2; // ID do pai. OBS: se resultar em número decimal, a parte decimal é ignorada. Por exemplo: 0.5 é 0. 
    if (heap[pai]->retornaPrioridade() < heap[indice]->retornaPrioridade()){ // se a prioridade do pai for menor que a do índice
      std::swap(heap[pai], heap[indice]); // coloca o objeto pai na posição do índice
      indice = pai; // o ID do índice recebe o ID do pai
    } else {
      break; // encerra o while se a prioridade do pai for igual ou maior que a do índice
    }
  }
}

// imprime e remove o documento que é o nó máximo (topo) da árvore e também pode fazer os demais documentos 'subirem' na árvore
Documento* Fila::imprimir(){

  Documento* noMaximo = heap[0]; // o objeto noMaximo é o topo
  heap[0] = heap.back(); // coloca no topo o objeto abaixo
  heap.pop_back(); // remove o objeto abaixo (antigo topo) 

  int indice = 0;
  while(indice < heap.size()){ // enquanto o índice for menor que a árvore
    int filhoEsquerdo = indice * 2 + 1; // ID do filhoEsquerdo
    int filhoDireito = indice * 2 + 2; // ID do filhoDireito
    int filhoGrande = filhoEsquerdo; // ID do filho de maior prioridade é o do filhoEsquerdo

    // se o ID do filhoDireito for menor que o tamanho da árvore e, ao mesmo tempo, a prioridade do filhoDireito for maior que a do filhoEsquerdo
    if(filhoDireito < heap.size() && heap[filhoDireito]->retornaPrioridade() > heap[filhoEsquerdo]->retornaPrioridade()){
      filhoGrande = filhoDireito; //filhoMaior recebe o filhoDireito, isto é, o filhoDireito sobe na árvore
    }

    // se o ID do filhoMaior for menor que o tamanho da árvore e, ao mesmo tempo, a prioridade do filho maior for maior que a prioridade do 'índice' 
    if(filhoGrande < heap.size() && heap[filhoGrande]->retornaPrioridade() > heap[indice]->retornaPrioridade()){
      std::swap(heap[filhoGrande], heap[indice]); // coloca o filhoMaior na posição do índice
      indice = filhoGrande; // o ID do índice recebe o ID do filhoMaior
    } else {
      break; // encerra o while se o filhoMaior for maior ou igual ao tamanho da árvore ou a prioridade do filhoMaior for menor ou igual que a do índice
    }
  }
  
  return noMaximo; // retorna o noMáximo, ou seja, o topo
}

// returna true se a árvore estiver vazia ou false se a árvore estiver cheia
bool Fila::estaVazia(){
  return heap.empty(); 
}
